#ifndef __STREAM_READER__
#define __STREAM_READER__

#include "data_stream.h"
#include "guid.h"

class StreamReader
{
public:
	explicit StreamReader(DataStream& ds) : dataStream_(ds), stream_(ds.stream_), readPtr_(0) {}

	virtual ~StreamReader() {}

	inline DataStream* dataStream() {
		return &dataStream_;
	}

	inline void resetReadPtr() {
		readPtr_ = 0;
	}

	inline bool readEnd() {
		return readPtr_ >= dataStream_.stream_.size();
	}

	inline StreamReader& operator >> (bool& v) {
		uint8 value;
		readNumber(value);
		v = value == 1;
		return *this;
	}

	inline StreamReader& operator >> (int8& v) {
		return readNumber(v);
	}

	inline StreamReader& operator >> (uint8& v) {
		return readNumber(v);
	}

	inline StreamReader& operator >> (int16& v) {
		return readNumber(v);
	}

	inline StreamReader& operator >> (uint16& v) {
		return readNumber(v);
	}

	inline StreamReader& operator >> (int32& v) {
		return readNumber(v);
	}

	inline StreamReader& operator >> (uint32& v) {
		return readNumber(v);
	}

	inline StreamReader& operator >> (int64& v) {
		return readNumber(v);
	}

	inline StreamReader& operator >> (uint64& v) {
		return readNumber(v);
	}

	inline StreamReader& operator >> (Guid64& v) {
		uint64 value;
		readNumber(value);
		v = value;
		return *this;
	}

	inline StreamReader& operator >> (float32& v) {
		int32 value;
		readNumber(value);
		v = value / 100.0f;
		return *this;
	}

	inline StreamReader& operator >> (float64& v) {
		int64 value;
		readNumber(value);
		v = value / 100.0f;
		return *this;
	}

	inline StreamReader& operator >> (std::string& str) {
		str = "";
		if (readPtr_ + sizeof(int32) <= stream_.size()) {
			int32 sz = *(int32*)(stream_.data() + readPtr_);
			readPtr_ += sizeof(int32);
			if (readPtr_ + sz + 1 <= stream_.size()) {
				str = (const char*)stream_.data() + readPtr_;
				readPtr_ += sz + 1;
				return *this;
			}
			return *this;
		}
		shengine_assert(0);
		return *this;
	}

	inline StreamReader& operator >> (const char*& str) {
		str = "";
		if (readPtr_ + sizeof(int32) <= stream_.size()) {
			int32 sz = *(int32*)(stream_.data() + readPtr_);
			readPtr_ += sizeof(int32);
			if (readPtr_ + sz + 1 <= stream_.size()) {
				str = (const char*)stream_.data() + readPtr_;
				readPtr_ += sz + 1;
				return *this;
			}
			return *this;
		}
		shengine_assert(0);
		return *this;
	}

	inline StreamReader& operator >> (void*& udata) {
		uint64 v;
		operator >> (v);
		udata = (void*)v;
		return *this;
	}

	inline StreamReader& operator >> (std::vector<uint8>& v) {
		int32 sz = *(int32*)(stream_.data() + readPtr_);
		readPtr_ += sizeof(int32);
		shengine_assert((int32)stream_.size() - readPtr_ >= sz);
		if ((int32)stream_.size() - readPtr_ >= sz) {
			v.resize(sz);
			memcpy(v.data(), stream_.data() + readPtr_, sz);
			readPtr_ += sz;
		}
		return *this;
	}

private:
	template<typename _Ty>
	inline StreamReader& readNumber(_Ty& v) {
		if (readPtr_ + sizeof(v) <= stream_.size()) {
			v = *(_Ty*)(stream_.data() + readPtr_);
			readPtr_ += sizeof(v);
		}
		else {
			shengine_assert(0);
			v = _Ty();
		}
		return *this;
	}
private:
	DataStream& dataStream_;
	std::vector<uint8>& stream_;
	int32 readPtr_;
};

#endif
